﻿/**
* @copyright     (c) 2012, by SwarmOnline.com
* @date          29th May 2012
* @version       0.1
* @documentation
* @website        http://www.swarmonline.com
*/
/**
* @class Ext.ux.TouchCalendarSimpleEvents
* @author Stuart Ashworth
*
* For use with Sencha Touch 2
*
* This plugin can be added to an Ext.ux.TouchCalendarView instance to allow a store to be bound to the calendar so events can be shown in a similar style to the iPhone
* does with a dot added to each day to represent the presence of an event.
* 
* ![Ext.ux.TouchCalendarSimpleEvents Screenshot](http://www.swarmonline.com/Ext.ux.TouchCalendar/screenshots/Ext.ux.TouchCalendarSimpleEvents-month-ss.png)
* 
* # Sample Usage
* 
*     Ext.regModel('Event', {
fields: [{
name: 'event',
type: 'string'
}, {
name: 'location',
type: 'string'
}, {
name: 'start',
type: 'date',
dateFormat: 'c'
}, {
name: 'end',
type: 'date',
dateFormat: 'c'
}]
});
       
var calendar = new Ext.ux.Calendar({
fullscreen: true,
mode: 'month',
weekStart: 1,
value: new Date(),
           
store: new Ext.data.Store({
model: 'Event',
data: [{
event: 'Sencha Con',
location: 'Austin, Texas',
start: new Date(2011, 9, 23),
end: new Date(2011, 9, 26)
}]
},
                        
plugins: [new Ext.ux.CalendarSimpleEvents()]
});
*    
* # Demo
* [Ext.ux.CalendarSimpleEvents Demo](http://www.swarmonline.com/Ext.ux.TouchCalendar/examples/Ext.ux.CalendarSimpleEvents.html)
*/
Ext.define('Ext.ux.TouchCalendarSimpleEvents', {
    extend: 'Ext.mixin.Observable',

    /**
    * @cfg {String} startEventField Name of the Model field which contains the Event's Start date
    */
    startEventField: 'start',

    /**
    * @cfg {Stirng} endEventField Name of the Model field which contains the Event's End date
    */
    endEventField: 'end',

    /**
    * @cfg {Boolean} multiEventDots True to display a dot for each event on a day. False to only show one dot regardless
    * of how many events there are
    */
    multiEventDots: true,

    /**
    * @cfg {String} wrapperCls CSS class that is added to the event dots' wrapper element
    */
    wrapperCls: 'simple-event-wrapper',

    /**
    * @cfg {String} eventDotCls CSS class that is added to the event dot element itself. Used to provide
    * the dots' styling
    */
    eventDotCls: 'simple-event',

    /**
    * @cfg {Number} dotWidth Width in pixels of the dots as defined by CSS. This is used for calculating the positions and
    * number of dots able to be shown.
    */
    dotWidth: 6,

    /**
    * @cfg {String} eventTpl Template used to create the Event markup. Template is merged with the records left
    * following the filter
    * 
    */
    eventTpl: ['<span class="{wrapperCls}">',
		'<tpl for="events">',
			'<span class="{[parent.eventDotCls]}"></span>',
		'</tpl>',
	'</span>'].join(''),

    /**
    * Function used to filter the store for each of the displayed dates
    * @method
    * @private
    * @param {Object} record - current record
    * @param {Object} id - ID of passed in record
    * @param {Object} currentDate - date we are currently dealing while looping Calendar's dateCollection property
    */
    filterFn: function (record, id, currentDate) {
        if (arguments.length === 2) {
            currentDate = id;
        }
        var startDate = Ext.Date.clearTime(record.get(this.startEventField), true).getTime(),
			endDate = Ext.Date.clearTime(record.get(this.endEventField), true).getTime(),
			currentDate = Ext.Date.clearTime(currentDate, true).getTime();

        return (startDate <= currentDate) && (endDate >= currentDate);
    },

    init: function (calendar) {
        this.calendar = calendar; // cache the parent calendar
        this.calendar.simpleEventsPlugin = this; // cache the plugin instance on the calendar itself

        this.wrapperCls = this.wrapperCls + (this.multiEventDots ? '-multi' : '');
        this.eventDotCls = this.eventDotCls + (this.multiEventDots ? '-multi' : '');

        this.calendar.showEvents = this.showEvents;
        this.calendar.hideEvents = this.hideEvents;
        this.calendar.removeEvents = this.removeEvents;

        // After the calendar's refreshed we must refresh the events
        this.calendar.refresh = Ext.Function.createSequence(this.calendar.refresh, this.refreshEvents, this);
        this.calendar.syncHeight = Ext.Function.createSequence(this.calendar.syncHeight, this.refreshEvents, this);
    },


    /**
    * Function to execute when the Calendar is refreshed.
    * It loops through the Calendar's current dateCollection and gets all Events
    * for the current date and inserts the appropriate markup
    * @method
    * @private
    * @return {void}
    */
    refreshEvents: function () {
        if (!this.disabled) {
            var datesStore = this.calendar.getStore();

            if (datesStore) {

                this.removeEvents(); // remove the event dots already existing

                // loop through Calendar's current dateCollection
                datesStore.each(function (dateObj) {
                    var date = dateObj.get('date');

                    var cell = this.calendar.getDateCell(date); // get the table cell for the current date
                    var store = this.calendar.eventStore;

                    if (cell && store != null) {
                        store.clearFilter();

                        // if we only want to show a single dot per day then use findBy for better performance
                        var matchIndex = store[this.multiEventDots ? 'filterBy' : 'findBy'](Ext.bind(this.filterFn, this, [date], true));
                        var eventCount = store.getRange().length;

                        if ((!this.multiEventDots && matchIndex > -1) || (this.multiEventDots && eventCount > 0)) {
                            // get maximum number of dots that can fitted in the cell
                            var maxDots = Math.min((cell.getWidth() / this.dotWidth), eventCount);

                            // append the event markup
                            var t = new Ext.XTemplate(this.eventTpl).append(cell, {
                                events: (this.multiEventDots ? store.getRange().slice(0, maxDots) : ['event']),
                                wrapperCls: this.wrapperCls,
                                eventDotCls: this.eventDotCls
                            }, true);

                            // position the dot wrapper based on the cell dimensions and dot count
                            t.setWidth(Math.min((this.multiEventDots ? store.getRange().length : 1) * this.dotWidth, cell.getWidth()));
                            t.setY((cell.getY() + cell.getHeight()) - (t.getHeight() + (cell.getHeight() * 0.1)));
                            t.setX((cell.getX() + (cell.getWidth() / 2)) - (t.getWidth() / 2) + 2); // add 2 for margin value
                        }
                    }
                }, this);
            }
        }
    },

    /**
    * Hides all the event markers
    * This is added to the parent Calendar's class so must be executed via the parent
    * @method
    * @return {void}
    */
    hideEvents: function () {
        this.simpleEventsPlugin.disabled = true;

        this.calendar.element.select('span.' + this.wrapperCls).hide();
    },

    /**
    * Shows all the event markers
    * This is added to the parent Calendar's class so must be executed via the parent
    * @method
    * @return {void}
    */
    showEvents: function () {
        this.simpleEventsPlugin.disabled = false;

        this.calendar.element.select('span.' + this.wrapperCls).show();
    },

    /**
    * Removes all the event markers and their markup
    * This is added to the parent Calendar's class so must be executed via the parent
    * @method
    * @return {void}
    */
    removeEvents: function () {
        if (this.calendar.element) {
            this.calendar.element.select('span.' + this.wrapperCls).remove();
        }
    }
});